import datetime
import http.client
import sched
import sys
import threading
import time
import urllib

from bigchaindb import Bigchain
from bson import ObjectId
from rest_framework.decorators import api_view
from rest_framework.response import Response

b = Bigchain()


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_blocks(request, format=None):
    """
    """
    print('----get_blocks--start----', time.time())
    limt = request.GET.get('limit')
    starttst = request.GET.get('blockDate')
    pagination = {}
    requlist = []
    if starttst != None:
        today = datetime.date.today()
        time_local = time.localtime(int(starttst))
        pagination['current'] = time.strftime('%Y-%m-%d',time_local)
        pagination['currentTs'] = starttst
        isToday = False
        if pagination['current'] == today.strftime('%Y-%m-%d'):
            isToday = True
        pagination['next'] = time.strftime('%Y-%m-%d',  time.localtime(int(starttst) + 86400))
        pagination['prev'] = time.strftime('%Y-%m-%d', time.localtime(int(starttst) - 86400))
        pagination['more'] = False
        pagination['isToday'] = isToday
        pagination['nextTs'] = int(starttst) + 86400
        pagination['prevTs'] = int(starttst) - 86400
        starttst = int(starttst)
        end = starttst + 24 * 60 * 60

        list_mongo = [
            {'$match': {'$and': [{'_id': {'$gt': ObjectId.from_datetime(datetime.datetime.utcfromtimestamp(starttst))}},
                               {'_id': {'$lt': ObjectId.from_datetime(datetime.datetime.utcfromtimestamp(end))}}]
                      }},
            {'$sort':{"_id":-1}},
            {'$match': {'$and': [{'_id': {'$gt': ObjectId.from_datetime(datetime.datetime.utcfromtimestamp(starttst))}},
                               {'_id': {'$lt': ObjectId.from_datetime(datetime.datetime.utcfromtimestamp(end))}}]
                      }}
        ]

    else:
        if limt == None:
            initlist()
            for i in range(len(mongolist_xiangxi)):
                requlist.insert(0, mongolist_xiangxi[i])
            response = {'blocks': requlist, 'length': len(requlist), 'pagination': pagination}
            print('----get_blocks--end----', time.time())
            return Response(data=response)
        else:
            limt = int(limt)
            list_mongo = [#{'$match': {}},
            {'$sort':{"_id":-1}},
            {'$limit':limt},
            #{'$match': {}}
        ]

    blocks = b.getbolcks(list_mongo)
    print('----b.getTxByList(list_mongo)----', time.time())
    print('----len(blocks)-----', len(blocks))
    # lenght = 0
    # if limt == None:
    #     limt = len(blocks)
    # else:
    #     limt = int(limt)
    #
    # if len(blocks) > limt:
    #     lenght = limt
    # else:
    #     lenght = len(blocks)


    print('----initlist--start----', time.time())
    initlist()
    print('----initlist--end----', time.time())

    for i in range(len(blocks)):
        bid = {'id': blocks[-(i + 1)]['id']}
        bl = {'height': mongolist.index(bid) + 1}
        bl['hash'] = blocks[-(i + 1)]['id']
        bl['time'] = blocks[-(i + 1)]['block']['timestamp']
        bl['txlength'] = len(blocks[-(i + 1)]['block']['transactions'])
        requlist.insert(0,bl)
    response = {'blocks': requlist, 'length': len(requlist), 'pagination':pagination}
    print('----get_blocks--end----', time.time())
    return Response(data=response)


def object_id_from_datetime(from_datetime=None, span_days=0, span_hours=0, span_minutes=0, span_seconds=0,
                            span_weeks=0):
    '''根据时间手动生成一个objectid，此id不作为存储使用'''
    if not from_datetime:
        from_datetime = datetime.datetime.now()
    from_datetime = from_datetime + datetime.timedelta(days=span_days, hours=span_hours, minutes=span_minutes,
                                                       weeks=span_weeks)
    return ObjectId.from_datetime(generation_time=from_datetime)


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_block_byhash(request, key, format=None):
    """
    """
    blockHash = key

    list_mongo =[
            {'$match': {'id': blockHash}},
            {'$match': {'id': blockHash}}
        ]
    print('----list_mongo----', list_mongo)

    blocks = b.getbolcks(list_mongo)
    # print('----get_blocks----', blocks)
    if blocks == None or len(blocks) == 0:
        return Response({'error': 'no block hash is ' + blockHash})

    bl = {}
    bl['hash'] = blocks[0]['id']
    bl['time'] = blocks[0]['block']['timestamp']
    bl['size'] = sys.getsizeof(blocks[0])
    tx = []
    for i in range(len(blocks[0]['block']['transactions'])):
        tx.append(blocks[0]['block']['transactions'][i]['id'])
    bl['tx'] = tx
    initlist()
    bb = {'id': blockHash}
    index = mongolist.index(bb)
    bl['height'] = index + 1
    if len(mongolist) == 0:
        pass
    elif len(mongolist) == 1:
        bl['previousblockhash'] = ''
        bl['nextblockhash'] = ''
    elif index == 0:
        bl['previousblockhash'] = ''
        bl['nextblockhash'] = mongolist[index + 1]['id']
    elif index == len(mongolist) - 1:
        bl['previousblockhash'] = mongolist[index - 1]['id']
        bl['nextblockhash'] = ''
    else:
        bl['previousblockhash'] = mongolist[index - 1]['id']
        bl['nextblockhash'] = mongolist[index + 1]['id']
    return Response(data=bl)


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_block_height(request, key, format=None):
    """
    """
    blockHeight = key
    blockHeight = int(blockHeight)
    initlist()
    if len(mongolist) < blockHeight:
        return Response({'error': 'mei you'})
    bl = {'blockHash': mongolist[blockHeight - 1]['id']}
    return Response(data=bl)


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_tx_bytxid(request, key, format=None):
    """
    """
    txid = key
    mongo_lis = [
        {'$match': {'block.transactions.id': txid}},
        {'$unwind': '$block.transactions'},
        {'$match': {'block.transactions.id': txid}}
    ]
    txs = b.getTxByList(mongo_lis)
    if txs is None or len(txs) == 0:
        return Response({'error': 'no transaction id is ' + txid})
    blockhash =  b.get_blockhash_bytxid(txid)
    txs[0]['blockhash'] = blockhash
    bl = {'transactions': txs[0]}
    return Response(data=bl)


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_txs_fromblock(request, format=None):
    """
    """
    print('----get_blocks--start----', time.time())
    blockHash = request.GET.get('block')
    pubkey = request.GET.get('address')
    bl = {}
    if blockHash is not None:
        list_mongo = [
            {'$match': {'id': blockHash}},
            {'$match': {'id': blockHash}}
        ]
        blocks = b.getbolcks(list_mongo)
        if blocks == None or len(blocks) == 0:
            return Response({'error': 'no block hash is ' + blockHash})

        # txs = []
        # for i in range(len(blocks['block']['transactions'])):
        #     tx = {'txid':blocks['block']['transactions'][i]['id']}
        #     pass

        bl = blocks[0]
        del bl['_id']
        del bl['signature']
        del bl['block']['voters']
        return Response(data=bl)
    elif pubkey is not None:
        list_mongo = [
            {'$match': {'$or': [{'block.transactions.outputs.public_keys': pubkey},
                                {'block.transactions.inputs.owners_before': pubkey}]}},
            {'$unwind': '$block.transactions'},
            {'$match': {'$or': [{'block.transactions.outputs.public_keys': pubkey},
                                {'block.transactions.inputs.owners_before': pubkey}]}}
        ]
        txs = b.getTxByList(list_mongo)

        bl['PubKey_id'] = pubkey
        bl['transactions'] = txs
        return Response(data=bl)
    else:
        return Response({'error': ''})


# Check that tag is in data and return data[tag]
def candr(data, tag):
    if tag in data:
        return data[tag]
    else:
        return ''


@api_view(['GET'])
# @permission_classes((Or(IsAdmin, IsManager),))
def get_txsinfo_bypubkey(request, key, format=None):
    """
    """
    pubkey = key

    list_mongo = [
        {'$match': {'$or': [{'block.transactions.outputs.public_keys': pubkey},
                            {'block.transactions.inputs.owners_before': pubkey}]}},
        {'$unwind': '$block.transactions'},
        {'$match': {'$or': [{'block.transactions.outputs.public_keys': pubkey},
                            {'block.transactions.inputs.owners_before': pubkey}]}}
    ]
    bl = {'addrStr': pubkey, 'totalReceived': 0, 'totalSent': 0, 'billtotalReceived': 0, 'billtotalSent': 0}
    curser = b.getTxByList(list_mongo)
    if curser is None or len(curser) == 0:
        return Response({'error': 'no transaction addr is ' + pubkey})
    for block in curser:
        if block['metadata']['asset'] == 'money RMB':
            if 'to' in block['metadata']:
                if block['inputs'][0]['owners_before'][0] == pubkey:
                    #out
                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pubkey:
                            #zhao ling
                            pass
                        else:
                            bl['totalSent'] = block['outputs'][i]['amount'] + bl['totalSent']
                else:
                    #in
                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pubkey:

                            bl['totalReceived'] = block['outputs'][i]['amount'] + bl['totalReceived']
                        else:
                            pass
            elif 'from' in block['metadata']:
                for i in range(len(block['outputs'])):
                    if block['outputs'][i]['public_keys'][0] == pubkey:
                        bl['totalReceived'] = block['outputs'][i]['amount'] + bl['totalReceived']
                    else:
                        pass
        elif block['metadata']['asset'] == 'bill':
            if 'to' in block['metadata']:
                if block['inputs'][0]['owners_before'][0] == pubkey:
                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pubkey:
                            pass
                        else:
                            bl['billtotalSent'] = block['outputs'][i]['amount'] + bl['billtotalSent']
                else:
                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pubkey:
                            bl['billtotalReceived'] = block['outputs'][i]['amount'] + bl['billtotalReceived']
                        else:
                            pass
            elif 'from' in block['metadata']:
                for i in range(len(block['outputs'])):
                    if block['outputs'][i]['public_keys'][0] == pubkey:
                        bl['billtotalReceived'] = block['outputs'][i]['amount'] + bl['billtotalReceived']
                    else:
                        pass

    bl['balance'] = bl['totalReceived'] - bl['totalSent']
    bl['billbalance'] = bl['billtotalReceived'] - bl['billtotalSent']
    bl['txApperances'] = len(curser)

    return Response(data=bl)


@api_view(['GET'])
def get_blockhash_bytransaction_id(request, key, format=None):
    transaction_id = key
    bl = b.get_blockhash_bytxid(transaction_id)
    return Response(data=bl)


mongolist = []
mongolist_xiangxi = []
def initlist():
    # mongolist.clear()
    if len(mongolist) == 0:
        list_mongo = [
            {'$sort':{"_id":1}},
        ]
        blocks = b.getbolcks(list_mongo)
        # for i in range(len(blocks)):
        #     bl = {'id': blocks[i]['id']}
        #     # bl['height'] = i + 1
        #     mongolist.append(bl)
    else:
        id = mongolist[-1]['id']

        blockHash = id
        #
        # list_mongo = [
        #     {'$match': {'id': blockHash}},
        #     {'$match': {'id': blockHash}}
        # ]
        # print('----list_mongo----', list_mongo)
        #
        # blocks = b.getbolcks(list_mongo)
        # # print('----get_blocks----', blocks)
        # # if blocks == None or len(blocks) == 0:
        # #     return Response({'error': 'no block hash is ' + blockHash})
        #
        # bl = {}
        # bl['time'] = blocks[0]['block']['timestamp']
        time_block = mongolist_xiangxi[mongolist.index({'id':blockHash})]['time']
        list_mongo2 = [
            # {'$match': {'block.timestamp': {'$gt':bl['time']}}},
            {'$match': {'block.timestamp': {'$gt':time_block}}},
            {'$sort': {"_id": 1}},
        ]
        blocks = b.getbolcks(list_mongo2)
    for i in range(len(blocks)):
        bl = {'id': blocks[i]['id']}
        if bl in mongolist:
            continue
        mongolist.append(bl)
        bl = {'time': blocks[i]['block']['timestamp']}
        bid = {'id': blocks[i]['id']}
        bl['height'] = mongolist.index(bid) + 1
        bl['hash'] = blocks[i]['id']
        bl['txlength'] = len(blocks[i]['block']['transactions'])
        mongolist_xiangxi.append(bl)


txs = []
#zdz
def transactionsall():
    txs.clear()
    transactions = b.get_transactions_all()
    for x in transactions:
        txs.append(x)
#zdz
def transactionsTime(time):
    txs1 = []
    response = b.get_transactionsbytime(time)
    for x in response:
        txs1.append(x)
    return txs1



#zdz to bloackweb
def to_chainweb_txs(txinfo):
    print('--------------->to_chainweb_txs')
    str = urllib.parse.urlencode(txinfo)
    header = {"Content-Type": "application/json",
              }
    conn = http.client.HTTPConnection("39.107.72.185", port=3001, source_address=None, timeout=5)
    conn.request(method="POST", url="/v1/newTx", body=str)
    response = conn.getresponse()
    response.close()


#zdz to bloackweb
def to_chainweb_block():
    print('==============>to_chainweb_block')
    header = {"Content-Type": "application/json",
              }
    conn = http.client.HTTPConnection("39.107.72.185", port=3001, source_address=None, timeout=5)
    conn.request(method="GET", url="/v1/newBlock", headers=header)
    response = conn.getresponse()
    response.close()

#zdz transactionn timer
def fun_timer_txs():
    if len(txs) == 0:
        transactionsall()
    pass
    time = txs[-1]['block']['transactions'][0]['metadata']['clientID']
    # print('fun_timer_txs------->',time)
    txs1 = transactionsTime(time)
    if len(txs1) != 0:
        print('-------len(txs1) != 0------->')
        txs.extend(txs1)
        for i in range(len(txs1)):
            map = {}
            map['txid'] = txs1[i]['block']['transactions'][0]['id']
            map['outValue'] = txs1[i]['block']['transactions'][0]['outputs'][0]['amount']
            print('test')
            to_chainweb_txs(map)
    else:
        pass
    # schedule.enter(3, 0, fun_timer_txs)

#zdz block timer
def fun_timer_block():
    # print("fun_timer_block")
    num1 = len(mongolist)
    if num1 == 0:
        initlist()
    else:
        initlist()
        num2 = len(mongolist)
        if num1 == num2:
            pass
        else:
            to_chainweb_block()
    # schedule.enter(3, 0, fun_timer_block)

# schedule = sched.scheduler(time.time, time.sleep)
# schedule2 = sched.scheduler(time.time, time.sleep)
#
# def while_update():
#     schedule.enter(0, 0, fun_timer_txs)
#     schedule.enter(0, 0, fun_timer_block)
#     schedule.run()





